/*
 * Copyright 2010 Alessandro Bellucci
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package org.soupframework.gwt.designerpanel.client.designer.impl;

import java.util.ArrayList;
import java.util.List;

import org.soupframework.gwt.designerpanel.client.designer.ContainerDesigner;
import org.soupframework.gwt.designerpanel.client.designer.Designer;
import org.soupframework.gwt.designerpanel.client.designer.DesignerManager;

import com.google.gwt.event.shared.EventHandler;
import com.google.gwt.event.shared.GwtEvent;
import com.google.gwt.event.shared.HandlerManager;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.ui.Panel;

public abstract class DesignerBase<T> implements Designer<T> {

	/**
	 * Operations
	 */
	protected Operations operations;

	/**
	 * The manager
	 */
	private DesignerManager<T> manager;

	/**
	 * Parent designer of this designer
	 */
	private ContainerDesigner<T> parent;

	/**
	 * Reference to the object being designed by this designer
	 */
	private T object;

	/**
	 * Manager responsible for adding handlers to event sources and firing those
	 * handlers on passed in events.
	 */
	private HandlerManager handlerManager;

	public DesignerBase(DesignerManager<T> manager, ContainerDesigner<T> parent, T object) {
		this.manager = manager;
		this.parent = parent;
		this.object = object;
		/*if(this.parent != null){
			((ContainerDesignerBase<T>)this.parent).addChildDesigner(this);
		}*/
	}

	public abstract class Operations implements Designer.Operations<T> {	
	}

	@Override
	public DesignerManager<T> getManager(){
		return this.manager;
	}

	@Override
	public T getObject(){
		return this.object;
	}

	@Override
	public String getObjectDescrition(T object){
		return object != null ? object.getClass().getName() : null;
	}

	@Override
	public ContainerDesigner<T> getParent() {
		return parent;
	}

	protected void setParent(ContainerDesigner<T> parent){
		this.parent = parent;
	}

	@Override
	public void openContextMenu(int preferredLeft, int preferredTop){
		if(this.getManager().getContextMenuFactory() != null){
			List<T> objects = new ArrayList<T>();
			objects.add(this.getObject());
			Panel contextMenu = this.getManager().getContextMenuFactory().getContextMenu(objects);
			this.getManager().getDesignerPanel().showContextMenu(objects, contextMenu, preferredLeft, preferredTop);
		}
	}

	/**
	* Ensures the existence of the handler manager.
	*
	* @return the handler manager
	*/
	HandlerManager ensureHandlers() {
		return handlerManager == null ? handlerManager = new HandlerManager(this) : handlerManager;
	}

	/**
	 * Returns the handler manager
	 *
	 * @return the handler manager
	 */
	HandlerManager getHandlerManager() {
		return handlerManager;
	}

	/**
	* Adds this handler to the designer.
	* 
	* @param <H> the type of handler to add
	* @param type the event type
	* @param handler the handler
	* @return {@link HandlerRegistration} used to remove the handler
	*/
	protected final <H extends EventHandler> HandlerRegistration addHandler(final H handler, GwtEvent.Type<H> type) {
		return ensureHandlers().addHandler(type, handler);
	}

	@Override
	public void fireEvent(GwtEvent<?> event) {
		if(this.handlerManager != null) {
			this.handlerManager.fireEvent(event);
		}

		if(this.parent != null){
			this.parent.fireEvent(event);
		}
	}

	@Override
	public void refresh() {
	}
}
